package com.smartcommunity.service.dataImport;

import cn.hutool.core.util.StrUtil;
import com.smartcommunity.base.bean.ExceptionCode;
import com.smartcommunity.base.common.DataImport;
import com.smartcommunity.controller.DataImportBase;
import com.smartcommunity.dao.system.SysOrgDao;
import com.smartcommunity.entity.system.SysOrgEntity;
import com.smartcommunity.exception.BusinessException;
import com.smartcommunity.log.interceptor.Log;
import com.smartcommunity.service.dataImport.model.SysOrgExportModel;
import com.smartcommunity.utils.BeanMapUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.map.HashedMap;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.servlet.http.HttpServletResponse;
import java.util.*;
import java.util.stream.Collectors;

import static org.apache.commons.lang3.StringUtils.EMPTY;

/**
 * 导入组织机构
 */
@Component
@Slf4j
public class SysOrgImport extends DataImportBase implements DataImport {

    @Autowired
    private SysOrgDao sysOrgDao;


    /**
     * 内容标题
     */
    private  String[] headerTitle = new String[]{
            "组织机构编号",
            "组织机构名称",
            "自定义上级组织机构编号",
            "系统中已存在的上级组织机构编号",
            "组织机构类型"
    };

    /**
     * 错误信息
     */
    private  String[] headerErrorMsg = new String[]{
            "组织机构编号为空",
            "组织机构名称不可为空",
            "第三列与第四列不可同时存在值",
            "第三列与第四列不可同时为空",
            "组织机构编号在系统中不存在"
    };

    /**
     * key taskId,value progress
     */
    final int cacheSize = 100000;
    Map<String, Integer> progressTag = new LinkedHashMap<String, Integer>((int) Math.ceil(cacheSize / 0.75f) + 1, 0.75f, true) {
        @Override
        protected boolean removeEldestEntry(Map.Entry<String, Integer> eldest) {
            return size() > cacheSize;
        }
    };

    @Transactional
    @Override
    @Log(info = "组织机构导入")
    public String importData(List list, String villageCode, String fileName,String taskId,HttpServletResponse response) throws IllegalArgumentException, BusinessException {
        progressTag.put(taskId,10);
        List<SysOrgEntity> insertList = new ArrayList<>();
        List<Object[]> objList = (List<Object[]>) list;
        //存储错误信息
        List<SysOrgExportModel> dataListCopy = new ArrayList<>();
        SysOrgEntity orgBean;
        int errorCount = 0;
        int size = objList.size();
        Map<String, List<Object[]>> selfParentCodeMap = new HashedMap();
        List<String> orgCodeList = new ArrayList<>();
        for (int i = 0; i < size; i++) {
            boolean isError = false;
            Object[] objects = objList.get(i);

            // 列长度校验，防止导入文件的列被删除
            int fixColumnLen = 5;
            if(objects.length < fixColumnLen){
                throw new BusinessException("模板文件列数不对，请检查模板文件！");
            }

            // 空行校验，跳过空行
            List<String> oneLine = Arrays.stream(objects)
                    .map(o -> StrUtil.trim(Objects.toString(o, EMPTY)))
                    .collect(Collectors.toList());
            if(oneLine.stream().allMatch(StrUtil::isEmpty)){
                continue;
            }

            StringBuffer errorMessages = new StringBuffer();
            // 组织机构编号
            String orgCode = String.valueOf(objects[0]) == "null" ? "" : String.valueOf(objects[0]);
            if (StringUtils.isBlank(orgCode)) {
                continue;//组织机构编号为空的数据直接放弃
                /*throw new BusinessException(ExceptionCode.EQUIPMENT_VILLAGE_ORG_IMPORT_EXCEPTION_CODE,
                        "第" + (i + Constant.START_ROW) + "行,组织机构编号不可为空!");*/
            }

            // 组织机构名称
            String orgName = String.valueOf(objects[1]) == "null" ? "" : String.valueOf(objects[1]);
            if (StringUtils.isBlank(orgName)) {
                String errorMsg = appendErrorMsg(headerTitle[1], orgName, headerErrorMsg[1]);
                errorMessages.append(errorMsg);
                isError = true;
            }
            if (StringUtils.isNotEmpty(objects[2].toString()) && StringUtils.isNotEmpty(objects[3].toString())) {
                String errorMsg = appendErrorMsg(headerTitle[2], orgName, headerErrorMsg[2]);
                errorMessages.append(errorMsg);
                isError = true;
            }
            orgBean = new SysOrgEntity();
            orgBean.setOrgCode(orgCode);
            orgBean.setOrgName(orgName);
            if(!orgCodeList.contains(orgCode)) {
                orgCodeList.add(orgCode);
            }

            if (objects[4] != null && !objects[4].equals("")) {
                orgBean.setOrgType(Integer.valueOf(String.valueOf(objects[4])));
            }

            // 自定义上级组织机构编号
            String selfParentCode = String.valueOf(objects[2]) == "null" ? "" : String.valueOf(objects[2]);
            // 数据库中已存在的上级组织机构编号
            String DBParentCode = String.valueOf(objects[3]) == "null" ? "" : String.valueOf(objects[3]);
            if (StringUtils.isEmpty(selfParentCode) && StringUtils.isEmpty(DBParentCode)) {
                String errorMsg = appendErrorMsg(headerTitle[2], orgName, headerErrorMsg[3]);
                errorMessages.append(errorMsg);
                isError = true;
            } else {
                //如果没填DBParentCode  则按照自定义上级编号生成数据
                if (StringUtils.isEmpty(DBParentCode)) {
                    //这里设置parentName用于数据插入之后生成ID  再更新parentId
                    if (selfParentCode.equals("-1")) {
                        orgBean.setParentId(-1);
                        orgBean.setParentName("-1");
                    } else {
                        orgBean.setParentId(0);//由于数据insert之前没有生成ID  这里先用0  之后再更新
                        orgBean.setParentName(selfParentCode);
                    }
                } else {
                    //根据DBParentCode查出对应的数据库自增id
                    Integer parenId = sysOrgDao.getOrgIdByCode(DBParentCode);
                    if (parenId == null) {
                        String errorMsg = appendErrorMsg(headerTitle[3], orgName, headerErrorMsg[4]);
                        errorMessages.append(errorMsg);
                        isError = true;
                    }
                    orgBean.setParentId(parenId);
                    orgBean.setParentName("dbparent");
                }
                if(StringUtils.isNotEmpty(selfParentCode)){
                    if(!selfParentCodeMap.containsKey(selfParentCode)) {
                        selfParentCodeMap.put(selfParentCode, new ArrayList<>());
                    }
                    selfParentCodeMap.get(selfParentCode).add(objects);
                }
            }
            if(isError){
                errorCount++;
                SysOrgExportModel exportModel = new SysOrgExportModel();
                exportModel.setOrgCode(orgCode);
                exportModel.setOrgName(orgName);
                exportModel.setSelfParentCode(selfParentCode);
                exportModel.setDBParentCode(DBParentCode);
                exportModel.setOrgType((String) objects[4]);
                exportModel.setErrorMsg(errorMessages.toString());
                dataListCopy.add(exportModel);
            }else {
                insertList.add(orgBean);
            }
        }
        //判断是否存在自定义父节点
        for ( Map.Entry<String, List<Object[]>> entry : selfParentCodeMap.entrySet()){
            String selfParentCode = entry.getKey();
            if(!orgCodeList.contains(selfParentCode)){
                for (Object[] object:entry.getValue()) {
                    String objectSelfParentCode = String.valueOf(object[2]) == "null" ? "" : String.valueOf(object[2]);
                    String orgCode = String.valueOf(object[0]) == "null" ? "" : String.valueOf(object[0]);
                    String orgName =String.valueOf(object[1]) == "null" ? "" : String.valueOf(object[1]);
                    if(StringUtils.isEmpty(objectSelfParentCode)) continue;
                    boolean existError = false;
                    for (SysOrgExportModel exportModel: dataListCopy) {
                        if(exportModel.getSelfParentCode().equals(objectSelfParentCode)&&exportModel.getOrgCode().equals(orgCode)){
                            StringBuffer errorMessages = new StringBuffer(exportModel.getErrorMsg());
                            errorMessages.append(appendErrorMsg(headerTitle[2], exportModel.getOrgName(), "找不到[" + objectSelfParentCode + "]自定义父节点"));
                            existError = true;
                            break;
                        }
                    }
                    if(!existError){
                        errorCount++;
                        StringBuffer errorMessages = new StringBuffer();
                        errorMessages.append(appendErrorMsg(headerTitle[2], orgName, "找不到[" + objectSelfParentCode + "]自定义父节点"));
                        SysOrgExportModel exportModel = new SysOrgExportModel();
                        exportModel.setOrgCode(orgCode);
                        exportModel.setOrgName(orgName);
                        exportModel.setSelfParentCode(selfParentCode);
                        exportModel.setDBParentCode(String.valueOf(object[3]) == "null" ? "" : String.valueOf(object[3]));
                        exportModel.setOrgType((String) object[4]);
                        exportModel.setErrorMsg(errorMessages.toString());
                        dataListCopy.add(exportModel);
                    }
                }

            }
        }

        try {
            progressTag.put(taskId,20);
            //查出现在数据库中所有未删除的组织机构   数据库已存在该orgCode  则移除
            List<String> existOrgCodes = sysOrgDao.getOrgCodes();
            progressTag.put(taskId, 30);
            for (int i = 0; i < insertList.size(); i++) {
                if (existOrgCodes.contains(insertList.get(i).getOrgCode())) {
                    insertList.remove(i);
                    i--;
                }
            }
            if (!CollectionUtils.isEmpty(insertList)) {
                sysOrgDao.insertBatch(insertList);
                progressTag.put(taskId,50);
                //更新parentId
                //首先根据parentName聚合
                Map<String, List<SysOrgEntity>> parentNameMap = BeanMapUtil.mapList(insertList, "parentName");
                //再根据orgCode转成Map集合
                Map<String, SysOrgEntity> orgMap = BeanMapUtil.mapBean(insertList, "orgCode");
                for (Map.Entry<String, List<SysOrgEntity>> entry : parentNameMap.entrySet()) {
                    if (entry.getKey().equals("-1")) {
                        continue;
                    }
                    if (entry.getKey().equals("dbparent")) {
                        continue;
                    }
                    List<SysOrgEntity> sameParentOrgList = entry.getValue();
                    for (SysOrgEntity updateBean : sameParentOrgList) {
                        if (orgMap.get(String.valueOf(entry.getKey())) == null) {
                            progressTag.put(taskId, 100);
                            throw new BusinessException(ExceptionCode.EQUIPMENT_VILLAGE_ORG_IMPORT_EXCEPTION_CODE,
                                    "找不到[" + entry.getKey() + "]自定义父节点");
                        }
                        updateBean.setParentId(orgMap.get(String.valueOf(entry.getKey())).getId());
                        sysOrgDao.updateOrg(updateBean);
                    }
                }
            }
            //正常的数据需要导入进去，错误的数据返回到Excel
            if (errorCount>0) {
                String errorFileName = exportExcelToLocal(taskId,fileName,headerTitle,dataListCopy);
                progressTag.put(taskId,100);
                return errorFileName;
            }
        } catch (Exception e) {
            if (e instanceof BusinessException) {
                throw new BusinessException(ExceptionCode.EQUIPMENT_VILLAGE_ORG_IMPORT_EXCEPTION_CODE, e.getMessage());
            } else {
                throw new BusinessException(ExceptionCode.EQUIPMENT_VILLAGE_ORG_IMPORT_EXCEPTION_CODE, "组织机构导入失败，保存数据库异常！");
            }
        }
        log.info("组织机构导入完成");
        progressTag.put(taskId, 100);
        return "";
    }

    @Override
    public int getImportDataProgress(String taskId) {
        return progressTag.get(taskId) == null ? 0 : progressTag.get(taskId);
    }
}
